using System;
using System.Collections.Generic;
using SeataNet.Core.Common;

namespace SeataNet.Core.AT
{
    /// <summary>
    /// AT模式事务上下文
    ///
    /// 存储AT模式全局事务的运行时信息和状态。
    ///
    /// 职责：
    /// - 跟踪全局事务的XID、状态、超时时间
    /// - 管理所有分支事务的上下文列表
    /// - 记录事务的开始和结束时间
    /// - 提供事务生命周期的元数据
    ///
    /// 数据结构：
    /// - Xid：全局事务唯一标识符
    /// - Status：事务状态（Begin/Committing/Committed/Rollbacking/Rollbacked）
    /// - Branches：所有分支事务的上下文列表
    /// - BeginTime：事务开始时间（UTC）
    /// - EndTime：事务结束时间（UTC，可能为null）
    /// - Timeout：事务超时时间（毫秒）
    ///
    /// 生命周期：
    /// ```
    /// 1. Begin：创建上下文，Status=Begin
    /// 2. 执行业务逻辑：添加分支到Branches列表
    /// 3. Committing：进入提交阶段，Status=Committing
    /// 4. Committed/Rollbacked：事务完成，设置EndTime
    /// ```
    ///
    /// 使用场景：
    /// - GlobalTransaction内部使用，跟踪事务状态
    /// - 监控和日志记录，提供事务元数据
    /// - 事务恢复，根据上下文恢复事务状态
    ///
    /// 线程安全：
    /// - 通常在单线程中使用（ThreadLocal或AsyncLocal）
    /// - Branches列表不是线程安全的，需要外部同步
    ///
    /// 注意事项：
    /// - 所有时间使用UTC时间（避免时区问题）
    /// - EndTime为null表示事务未完成
    /// - Branches列表按添加顺序排列
    /// </summary>
    public class AtTransactionContext
    {
        /// <summary>
        /// 全局事务ID
        ///
        /// 全局事务的唯一标识符，由TC生成。
        ///
        /// 格式：IP:时间戳:序列号
        /// 示例："192.168.1.100:1703123456789:5678"
        ///
        /// 用途：
        /// - 标识全局事务
        /// - 关联所有分支事务
        /// - 传播到所有参与者
        /// </summary>
        public string Xid { get; set; }

        /// <summary>
        /// 事务ID（数值形式）
        ///
        /// Xid的数值表示，用于内部索引和查询。
        ///
        /// 注意事项：
        /// - 可能与Xid冗余
        /// - 主要用于数据库主键或索引
        /// </summary>
        public long TransactionId { get; set; }

        /// <summary>
        /// 事务状态
        ///
        /// 标识全局事务的当前状态。
        ///
        /// 状态流转：
        /// - Begin：事务开始
        /// - Committing：正在提交（第二阶段）
        /// - Committed：提交完成
        /// - Rollbacking：正在回滚（第二阶段）
        /// - Rollbacked：回滚完成
        ///
        /// 注意事项：
        /// - 状态变更需要同步到TC
        /// - 中间状态（Committing/Rollbacking）可能较短暂
        /// </summary>
        public TransactionStatus Status { get; set; }

        /// <summary>
        /// 超时时间（毫秒）
        ///
        /// 全局事务的超时时间，超过此时间TC会自动回滚。
        ///
        /// 默认值：60000ms（60秒）
        /// 推荐值：
        /// - 快速业务：5000-30000ms
        /// - 正常业务：60000-300000ms
        /// - 长时间业务：300000+ms
        ///
        /// 注意事项：
        /// - 超时时间从Begin开始计算
        /// - TC会定期检查超时事务
        /// - 超时后TC发起自动回滚
        /// </summary>
        public long Timeout { get; set; }

        /// <summary>
        /// 开始时间
        ///
        /// 全局事务开始的UTC时间。
        ///
        /// 用途：
        /// - 计算事务持续时间
        /// - 判断是否超时
        /// - 监控和审计
        ///
        /// 注意事项：
        /// - 使用UTC时间避免时区问题
        /// - 在构造函数中自动设置为当前时间
        /// </summary>
        public DateTime BeginTime { get; set; }

        /// <summary>
        /// 结束时间
        ///
        /// 全局事务结束的UTC时间（可能为null）。
        ///
        /// null：事务尚未完成
        /// 非null：事务已完成（提交或回滚）
        ///
        /// 用途：
        /// - 计算事务总耗时：EndTime - BeginTime
        /// - 判断事务是否完成
        /// - 监控和统计
        ///
        /// 注意事项：
        /// - 只有在Committed或Rollbacked状态下才设置
        /// - 中间状态（Committing/Rollbacking）不设置EndTime
        /// </summary>
        public DateTime? EndTime { get; set; }

        /// <summary>
        /// 分支事务列表
        ///
        /// 该全局事务下所有分支事务的上下文列表。
        ///
        /// 每个分支表示：
        /// - 一个本地事务（通常对应一个数据库）
        /// - 一个微服务的参与
        /// - 一个undo_log记录
        ///
        /// 用途：
        /// - 跟踪所有参与者
        /// - 第二阶段提交/回滚时遍历所有分支
        /// - 监控分支状态
        ///
        /// 注意事项：
        /// - 列表按分支注册顺序排列
        /// - 不是线程安全的，需要外部同步
        /// - 每个分支有独立的BranchId
        /// </summary>
        public List<AtBranchContext> Branches { get; set; } = new List<AtBranchContext>();

        /// <summary>
        /// 默认构造函数
        ///
        /// 创建新的AT事务上下文，初始化默认值。
        ///
        /// 初始化内容：
        /// - BeginTime：当前UTC时间
        /// - Status：TransactionStatus.Begin
        /// - Branches：空列表
        ///
        /// 使用场景：
        /// - GlobalTransaction.Begin()时创建上下文
        /// - 手动创建事务上下文（测试场景）
        /// </summary>
        public AtTransactionContext()
        {
            BeginTime = DateTime.UtcNow;
            Status = TransactionStatus.Begin;
        }

        /// <summary>
        /// 带参数的构造函数
        ///
        /// 创建AT事务上下文并指定XID和新事务标识。
        ///
        /// 参数说明：
        /// - xid：全局事务ID，通常由TC生成
        /// - isNew：是否是新事务
        ///   - true：新事务，Status=Begin
        ///   - false：已存在的事务，Status=Committing（传播场景）
        ///
        /// 使用场景：
        /// - 新事务：TM调用GlobalTransaction.Begin()
        /// - 传播事务：RM接收到传播的XID
        /// - 事务恢复：从持久化存储恢复事务
        ///
        /// 事务传播示例：
        /// ```
        /// // 服务A：创建新事务
        /// var context = new AtTransactionContext(xid, isNew: true);
        ///
        /// // 服务B：接收传播的事务
        /// var context = new AtTransactionContext(xid, isNew: false);
        /// ```
        ///
        /// 注意事项：
        /// - isNew=false时，状态设置为Committing（假设传播过来的事务正在提交）
        /// - BeginTime总是设置为当前UTC时间
        /// - Xid需要在创建前由TC生成
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <param name="isNew">是否是新事务（true=Begin, false=Committing）</param>
        public AtTransactionContext(string xid, bool isNew)
        {
            Xid = xid;
            BeginTime = DateTime.UtcNow;
            Status = isNew ? TransactionStatus.Begin : TransactionStatus.Committing;
        }
    }

    /// <summary>
    /// AT分支事务上下文
    ///
    /// 存储AT模式分支事务的运行时信息和状态。
    ///
    /// 职责：
    /// - 跟踪分支事务的ID、资源ID、锁键
    /// - 记录分支事务的状态和时间信息
    /// - 作为全局事务上下文（AtTransactionContext）的子元素
    /// - 提供分支事务的元数据用于监控和审计
    ///
    /// 数据结构：
    /// - BranchId：分支事务唯一标识符（由TC分配）
    /// - ResourceId：资源标识符（通常是数据库连接字符串的哈希值）
    /// - LockKey：全局锁键（表名:主键值）
    /// - Status：分支事务状态（PhaseOne_Done/PhaseTwo_Committed/PhaseTwo_Rollbacked等）
    /// - BeginTime：分支事务开始时间（UTC）
    /// - EndTime：分支事务结束时间（UTC，可能为null）
    ///
    /// 生命周期：
    /// ```
    /// 1. Begin：创建分支上下文，分配BranchId
    /// 2. 执行SQL：生成undo_log和LockKey
    /// 3. Register：向TC注册分支事务
    /// 4. PhaseOne_Done：本地事务提交完成
    /// 5. PhaseTwo_Committed/Rollbacked：二阶段完成，设置EndTime
    /// ```
    ///
    /// 与全局事务的关系：
    /// - 一个全局事务（AtTransactionContext）包含多个分支事务（AtBranchContext）
    /// - 每个分支对应一个本地数据库事务
    /// - 每个分支有独立的BranchId和Status
    /// - 所有分支共享同一个XID（全局事务ID）
    ///
    /// 使用场景：
    /// - AtConnectionProxy提交时创建分支上下文
    /// - 添加到AtTransactionContext.Branches列表
    /// - 第二阶段提交/回滚时遍历所有分支
    /// - 监控和日志记录分支状态
    ///
    /// 线程安全：
    /// - 通常在单线程中使用（ThreadLocal或AsyncLocal）
    /// - 属性访问不是线程安全的，需要外部同步
    /// - 添加到Branches列表时需要同步
    ///
    /// 注意事项：
    /// - 所有时间使用UTC时间（避免时区问题）
    /// - EndTime为null表示分支未完成
    /// - BranchId在注册成功后才有值
    /// - LockKey格式必须符合规范（表名:主键值）
    /// </summary>
    public class AtBranchContext
    {
        /// <summary>
        /// 分支事务ID
        ///
        /// TC分配的分支事务唯一标识符，用于标识全局事务中的一个分支。
        ///
        /// 分配时机：
        /// - 调用IAtTransactionManager.RegisterBranchAsync()时由TC分配
        /// - 在本地事务提交前完成分配
        /// - 分配成功后才能提交本地事务
        ///
        /// 用途：
        /// - 标识分支事务（全局唯一）
        /// - 第二阶段提交/回滚时指定目标分支
        /// - 上报分支状态时使用
        /// - 查询undo_log时作为查询条件
        ///
        /// 范围：
        /// - 类型：long（64位整数）
        /// - 范围：1 ~ 9223372036854775807
        /// - TC保证在全局范围内唯一
        ///
        /// 注意事项：
        /// - 注册失败时BranchId可能为0或默认值
        /// - 分支ID与全局事务ID（XID）配合使用
        /// - 不同全局事务的分支ID可能重复
        /// - undo_log表使用(xid, branch_id)作为复合主键
        /// </summary>
        public long BranchId { get; set; }

        /// <summary>
        /// 资源ID
        ///
        /// 标识分支事务所属的资源（通常是数据库）。
        ///
        /// 格式：
        /// - 通常是数据库连接字符串的哈希值
        /// - 或者自定义的资源标识符
        /// - 示例：\"jdbc:mysql://127.0.0.1:3306/seata\"
        ///
        /// 用途：
        /// - TC根据ResourceId路由分支事务到对应的RM
        /// - 标识分支事务操作的目标数据库
        /// - 分支注册时传递给TC
        /// - 资源管理器根据ResourceId管理连接
        ///
        /// 生成方式：
        /// - 方式1：连接字符串的哈希值（常用）
        /// - 方式2：数据库名称（如\"order-db\"）
        /// - 方式3：JDBC URL（完整路径）
        ///
        /// 注意事项：
        /// - 相同数据库的所有分支应使用相同的ResourceId
        /// - ResourceId用于RM识别和管理资源
        /// - 不同数据库必须使用不同的ResourceId
        /// - TC根据ResourceId发送提交/回滚指令
        /// </summary>
        public string ResourceId { get; set; }

        /// <summary>
        /// 全局锁键
        ///
        /// 标识分支事务需要申请的全局锁，防止脏写。
        ///
        /// 格式：
        /// - 单行：\"表名:主键值\"
        ///   示例：\"account_table:1001\"
        /// - 多行：\"表名:主键值1;主键值2;主键值3\"
        ///   示例：\"account_table:1001;1002;1003\"
        /// - 多表：\"表名1:主键值1^^^表名2:主键值2\"
        ///   示例：\"order_table:5001^^^order_item_table:6001\"
        ///
        /// 用途：
        /// - 向TC申请全局锁（防止其他事务修改相同记录）
        /// - 检测并发冲突（锁冲突时注册失败）
        /// - 第二阶段提交时释放全局锁
        /// - 全局锁在本地事务提交后依然保持
        ///
        /// 工作原理：
        /// ```
        /// 1. RM执行SQL时记录修改的主键
        /// 2. 生成LockKey（表名:主键值）
        /// 3. 本地事务提交前向TC申请全局锁
        /// 4. TC检查锁冲突：
        ///    - 无冲突：分配锁，注册成功
        ///    - 有冲突：注册失败，RM回滚本地事务
        /// 5. 本地事务提交后，全局锁保持
        /// 6. 二阶段提交时释放全局锁
        /// ```
        ///
        /// 注意事项：
        /// - LockKey格式必须正确，否则锁无效
        /// - 主键值必须是实际修改的记录的主键
        /// - 多个主键用分号分隔
        /// - 多个表用\"^^^\"分隔
        /// - LockKey为空时可能导致脏写
        /// </summary>
        public string LockKey { get; set; }

        /// <summary>
        /// 分支事务状态
        ///
        /// 标识分支事务当前的执行状态。
        ///
        /// 状态流转：
        /// ```
        /// PhaseOne_Done（一阶段完成）
        ///    ↓
        /// PhaseTwo_Committed（二阶段提交成功）
        /// 或
        /// PhaseTwo_Rollbacked（二阶段回滚成功）
        /// ```
        ///
        /// 状态说明：
        /// - PhaseOne_Done：本地事务提交成功，undo_log已写入
        /// - PhaseOne_Failed：本地事务提交失败，需要回滚
        /// - PhaseTwo_Committed：二阶段提交完成，undo_log已删除
        /// - PhaseTwo_CommitFailed_Retryable：二阶段提交失败，可重试
        /// - PhaseTwo_Rollbacked：二阶段回滚完成，数据已恢复
        /// - PhaseTwo_RollbackFailed_Retryable：二阶段回滚失败，可重试
        ///
        /// 状态变更时机：
        /// - PhaseOne_Done：AtConnectionProxy.Commit()完成后
        /// - PhaseTwo_Committed：AtDataSourceProxy删除undo_log后
        /// - PhaseTwo_Rollbacked：AtDataSourceProxy.Undo()完成后
        ///
        /// 使用场景：
        /// - 监控和日志记录分支状态
        /// - TC根据状态决定后续操作
        /// - 异常恢复时判断分支状态
        /// - 统计和审计分支执行情况
        ///
        /// 注意事项：
        /// - 状态变更需要上报给TC
        /// - 中间状态（Committing/Rollbacking）可能较短暂
        /// - Failed状态需要重试或人工介入
        /// - 状态不一致可能导致数据异常
        /// </summary>
        public BranchStatus Status { get; set; }

        /// <summary>
        /// 开始时间
        ///
        /// 分支事务开始的UTC时间。
        ///
        /// 用途：
        /// - 计算分支事务持续时间
        /// - 判断分支是否超时
        /// - 监控和审计分支执行情况
        /// - 统计分支事务性能指标
        ///
        /// 设置时机：
        /// - AtConnectionProxy创建分支上下文时设置
        /// - 在执行第一条SQL之前
        /// - 通常与全局事务的BeginTime接近
        ///
        /// 注意事项：
        /// - 使用UTC时间避免时区问题
        /// - 在构造函数或属性初始化时设置为DateTime.UtcNow
        /// - 用于计算分支执行耗时：EndTime - BeginTime
        /// - 不应该在执行过程中修改
        /// </summary>
        public DateTime BeginTime { get; set; }

        /// <summary>
        /// 结束时间
        ///
        /// 分支事务结束的UTC时间（可能为null）。
        ///
        /// null：分支尚未完成
        /// 非null：分支已完成（提交或回滚）
        ///
        /// 用途：
        /// - 计算分支总耗时：EndTime - BeginTime
        /// - 判断分支是否完成
        /// - 监控和统计分支执行时间
        /// - 审计和日志记录
        ///
        /// 设置时机：
        /// - PhaseTwo_Committed：二阶段提交完成时设置
        /// - PhaseTwo_Rollbacked：二阶段回滚完成时设置
        /// - 只有在最终状态（Committed/Rollbacked）时才设置
        ///
        /// 注意事项：
        /// - 使用UTC时间避免时区问题
        /// - null表示分支未完成（仍在执行或等待二阶段）
        /// - PhaseOne_Done状态不设置EndTime
        /// - 用于计算分支总耗时和超时判断
        /// </summary>
        public DateTime? EndTime { get; set; }
    }
}